package com.uinnova.product.eam.service.impl;

import com.binary.core.exception.BinaryException;
import com.binary.jdbc.Page;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.constant.MeasureConstant;
import com.uinnova.product.eam.dao.MeasureConfDao;
import com.uinnova.product.eam.dao.MeasureConfDetailDao;
import com.uinnova.product.eam.dto.IndicatorClassifyConf;
import com.uinnova.product.eam.dto.MeasureEvaluator;
import com.uinnova.product.eam.model.es.MeasureConf;
import com.uinnova.product.eam.model.es.MeasureConfDetail;
import com.uinnova.product.eam.service.AXEAConfService;
import com.uinnova.product.eam.service.ArchReviewExpertConfService;
import com.uinnova.product.eam.service.MeasureConfService;
import com.uinnova.product.eam.vo.ArchReviewExpertConfInfo;
import com.uinnova.product.eam.vo.MeasureConfHistory;
import com.uinnova.product.eam.vo.MeasureConfInfo;
import com.uinnova.product.eam.vo.MeasureConfSaveVo;
import com.uino.api.client.permission.IUserApiSvc;
import com.uino.bean.permission.base.SysUser;
import com.uino.bean.permission.query.CSysUser;
import com.uino.bean.sys.base.ESDictionaryClassInfo;
import com.uino.bean.sys.base.ESDictionaryItemInfo;
import com.uino.dao.sys.ESDictionaryClassSvc;
import com.uino.dao.sys.ESDictionaryItemSvc;
import com.uino.dao.util.ESUtil;
import com.uino.util.sys.SysUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Log4j2
public class MeasureConfServiceImpl implements MeasureConfService {

    @Autowired
    private MeasureConfDao measureConfDao;
    @Autowired
    private MeasureConfDetailDao measureConfDetailDao;
    @Autowired
    private ArchReviewExpertConfService archReviewExpertConfService;
    @Autowired
    private AXEAConfService axeaConfService;
    @Autowired
    private ESDictionaryClassSvc dictClsSvc;
    @Autowired
    private ESDictionaryItemSvc dictItemSvc;
    @Autowired
    private IUserApiSvc userApiSvc;

    @Override
    public List<MeasureEvaluator> evaluators(String group) {
        if (StringUtils.isBlank(group)) {
            throw new BinaryException("分组不能为空");
        }
        List<ArchReviewExpertConfInfo> infos = archReviewExpertConfService.expertConfInfo();
        if (CollectionUtils.isEmpty(infos)) {
            return new ArrayList<>();
        }
        List<MeasureEvaluator> measureEvaluators = new ArrayList<>();
        for (ArchReviewExpertConfInfo info : infos) {
            List<String> groupExperts = MeasureConstant.MEASURE_EVALUATOR_GROUP_A.equals(group) ? info.getGroupAExperts() : info.getGroupBExperts();
            if (CollectionUtils.isEmpty(groupExperts)) {
                continue;
            }
            measureEvaluators.add(new MeasureEvaluator(info.getId(), info.getDomain()));
        }
        return measureEvaluators;
    }

    @Override
    public List<String> indicatorClassifies() {
        IndicatorClassifyConf indicatorClassifyConf = axeaConfService.indicatorClassifyDictoryName();
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("domainId", 1L));
        query.must(QueryBuilders.termQuery("dictName.keyword", indicatorClassifyConf.getIndicatorClassifyDictoryName()));
        List<ESDictionaryClassInfo> dictClassInfos = dictClsSvc.getListByQuery(query);
        if (org.springframework.util.CollectionUtils.isEmpty(dictClassInfos)) {
            throw new BinaryException("字典表：" + indicatorClassifyConf.getIndicatorClassifyDictoryName() + "不存在");
        }
        Long dictClassId = dictClassInfos.get(0).getId();
        long count = dictItemSvc.countByCondition(QueryBuilders.termQuery("dictClassId", dictClassId));
        if (count == 0) {
            return new ArrayList<>();
        }
        List<ESDictionaryItemInfo> items = dictItemSvc.getListByQuery(1, new BigDecimal(count).intValue(),
                QueryBuilders.termQuery("dictClassId", dictClassId)).getData();
        List<String> res = new ArrayList<>();
        for (ESDictionaryItemInfo item : items) {
            Map<String, String> attrs = item.getAttrs();
            if (attrs.containsKey(indicatorClassifyConf.getIndicatorClassifyAttrName())) {
                res.add(attrs.get(indicatorClassifyConf.getIndicatorClassifyAttrName()));
            }
        }
        return res;
    }

    @Override
    public void saveMeasureConf(MeasureConfSaveVo saveVo) {
        checkPre(saveVo);
        String curUserLoginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        MeasureConf measureConf = new MeasureConf();
        measureConf.setId(ESUtil.getUUID());
        measureConf.setVersion(getMaxVersion() + 1);
        measureConf.setDesc(saveVo.getDesc());
        measureConf.setStatus(1);
        measureConf.setCreatorCode(curUserLoginCode);
        measureConf.setCreateTime(ESUtil.getNumberDateTime());
        measureConf.setModifierCode(curUserLoginCode);
        measureConf.setModifyTime(ESUtil.getNumberDateTime());

        List<MeasureConfDetail> details = new ArrayList<>();
        for (MeasureConfDetail detail : saveVo.getDetails()) {
            MeasureConfDetail measureConfDetail = EamUtil.copy(detail, MeasureConfDetail.class);
            measureConfDetail.setId(ESUtil.getUUID());
            measureConfDetail.setMeasureConfId(measureConf.getId());
            measureConfDetail.setCreatorCode(curUserLoginCode);
            measureConfDetail.setCreateTime(ESUtil.getNumberDateTime());
            measureConfDetail.setModifierCode(curUserLoginCode);
            measureConfDetail.setModifyTime(ESUtil.getNumberDateTime());
            details.add(measureConfDetail);
        }
        measureConfDao.saveOrUpdate(measureConf);
        measureConfDetailDao.saveOrUpdateBatch(details);
    }

    private void checkPre(MeasureConfSaveVo saveVo) {
        Assert.notNull(saveVo, "度量明细不能为空");
        Assert.notEmpty(saveVo.getDetails(), "度量明细不能为空");
        if (saveVo.getId() != null) {
            MeasureConf dbMeasureConf = measureConfDao.getById(saveVo.getId());
            Assert.notNull(dbMeasureConf, "未找到度量信息");
            Integer maxVersion = getMaxVersion();
            if (dbMeasureConf.getVersion() < maxVersion) {
                throw new BinaryException("历史版本度量配置不允许修改");
            }
        }

        Map<Long, List<String>> groupAMap = new HashMap<>();
        Map<Long, List<String>> groupBMap = new HashMap<>();
        List<ArchReviewExpertConfInfo> infos = archReviewExpertConfService.expertConfInfo();
        if (!CollectionUtils.isEmpty(infos)) {
            for (ArchReviewExpertConfInfo info : infos) {
                if (info.getGroupAExperts() == null) {
                    info.setGroupAExperts(new ArrayList<>());
                }
                if (info.getGroupBExperts() == null) {
                    info.setGroupBExperts(new ArrayList<>());
                }
                groupAMap.put(info.getId(), info.getGroupAExperts());
                groupBMap.put(info.getId(), info.getGroupBExperts());
            }
        }

        for (MeasureConfDetail detail : saveVo.getDetails()) {
            if (StringUtils.isBlank(detail.getIndicatorClassify())) {
                throw new BinaryException("指标分类不能为空");
            }
            if (StringUtils.isBlank(detail.getIndicatorDesc())) {
                throw new BinaryException("指标描述不能为空");
            }
            Assert.notNull(detail.getMaxScore(), "最高分不能为空");
            if (detail.getMaxScore() < 1 || detail.getMaxScore() > 100) {
                throw new BinaryException("最高分仅支持输入1-100整数");
            }
            if (!CollectionUtils.isEmpty(detail.getEvaluatorsA())) {
                for (MeasureEvaluator measureEvaluator : detail.getEvaluatorsA()) {
                    Assert.notNull(measureEvaluator.getId(), "【测评人员-A组】id不能为空");
                    Assert.notNull(measureEvaluator.getDomain(), "【测评人员-A组】领域名称不能为空");
                    String baseMsg = "【".concat(measureEvaluator.getDomain())
                            .concat("，")
                            .concat(measureEvaluator.getId().toString())
                            .concat("】");
                    if (!groupAMap.containsKey(measureEvaluator.getId())) {
                        throw new BinaryException(baseMsg.concat("已删除"));
                    }
                    if (CollectionUtils.isEmpty(groupAMap.get(measureEvaluator.getId()))) {
                        throw new BinaryException(baseMsg.concat("下无评审人员"));
                    }
                }
            }
            if (!CollectionUtils.isEmpty(detail.getEvaluatorsB())) {
                for (MeasureEvaluator measureEvaluator : detail.getEvaluatorsB()) {
                    Assert.notNull(measureEvaluator.getId(), "【测评人员-B组】id不能为空");
                    Assert.notNull(measureEvaluator.getDomain(), "【测评人员-B组】领域名称不能为空");
                    String baseMsg = "【".concat(measureEvaluator.getDomain())
                            .concat("，")
                            .concat(measureEvaluator.getId().toString())
                            .concat("】");
                    if (!groupBMap.containsKey(measureEvaluator.getId())) {
                        throw new BinaryException(baseMsg.concat("已删除"));
                    }
                    if (CollectionUtils.isEmpty(groupBMap.get(measureEvaluator.getId()))) {
                        throw new BinaryException(baseMsg.concat("下无评审人员"));
                    }
                }
            }
        }
    }

    private Integer getMaxVersion() {
        Page<MeasureConf> page = measureConfDao.getSortListByQuery(1, 1, QueryBuilders.boolQuery(), "version", false);
        return CollectionUtils.isEmpty(page.getData()) ? 0 : page.getData().get(0).getVersion();
    }

    @Override
    public MeasureConfInfo info(Long id) {
        Assert.notNull(id, "度量id不能为空");
        MeasureConf measureConf = measureConfDao.getById(id);
        Assert.notNull(measureConf, "未找到度量信息");
        TermQueryBuilder query = QueryBuilders.termQuery("measureConfId", id);
        Page<MeasureConfDetail> page = measureConfDetailDao.getSortListByQuery(1, 3000, query, "id", true);
        MeasureConfInfo measureConfInfo = EamUtil.copy(measureConf, MeasureConfInfo.class);
        measureConfInfo.setDetails(new ArrayList<>());
        if (CollectionUtils.isEmpty(page.getData())) {
            return measureConfInfo;
        }
        Set<Long> evaluatorIds = new HashSet<>();
        for (MeasureConfDetail detail : page.getData()) {
            if (!CollectionUtils.isEmpty(detail.getEvaluatorsA())) {
                evaluatorIds.addAll(detail.getEvaluatorsA().stream()
                        .map(MeasureEvaluator::getId).filter(Objects::nonNull).collect(Collectors.toSet()));
            }
            if (!CollectionUtils.isEmpty(detail.getEvaluatorsB())) {
                evaluatorIds.addAll(detail.getEvaluatorsB().stream()
                        .map(MeasureEvaluator::getId).filter(Objects::nonNull).collect(Collectors.toSet()));
            }
        }
        if (CollectionUtils.isEmpty(evaluatorIds)) {
            return measureConfInfo;
        }
        List<ArchReviewExpertConfInfo> infos = archReviewExpertConfService.expertConfInfo();
        Map<Long, String> evaluatorMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(infos)) {
            evaluatorMap = infos.stream().collect(Collectors.toMap(ArchReviewExpertConfInfo::getId, ArchReviewExpertConfInfo::getDomain));
        }
        List<MeasureConfDetail> details = page.getData();
        for (MeasureConfDetail detail : details) {
            if (!CollectionUtils.isEmpty(detail.getEvaluatorsA())) {
                List<MeasureEvaluator> evaluatorsA = detail.getEvaluatorsA();
                for (MeasureEvaluator measureEvaluator : evaluatorsA) {
                    String domain = evaluatorMap.get(measureEvaluator.getId());
                    if (StringUtils.isNotBlank(domain)) {
                        measureEvaluator.setDomain(domain);
                    }
                }
                detail.setEvaluatorsA(evaluatorsA);
            }
            if (!CollectionUtils.isEmpty(detail.getEvaluatorsB())) {
                List<MeasureEvaluator> evaluatorsB = detail.getEvaluatorsB();
                for (MeasureEvaluator measureEvaluator : evaluatorsB) {
                    String domain = evaluatorMap.get(measureEvaluator.getId());
                    if (StringUtils.isNotBlank(domain)) {
                        measureEvaluator.setDomain(domain);
                    }
                }
                detail.setEvaluatorsB(evaluatorsB);
            }
        }
        measureConfInfo.setDetails(details);
        return measureConfInfo;
    }

    @Override
    public MeasureConfInfo latestInfo() {
        TermQueryBuilder query = QueryBuilders.termQuery("version", getMaxVersion());
        List<MeasureConf> measureConfs = measureConfDao.getListByQuery(query);
        if (CollectionUtils.isEmpty(measureConfs)) {
            return null;
        }
        return info(measureConfs.get(0).getId());
    }

    @Override
    public List<MeasureConfHistory> histories() {
        Integer maxVersion = getMaxVersion();
        RangeQueryBuilder query = QueryBuilders.rangeQuery("version");
        query.lt(maxVersion);
        Page<MeasureConf> page = measureConfDao.getSortListByQuery(1, 3000, query, "createTime", false);
        if (CollectionUtils.isEmpty(page.getData())) {
            return null;
        }
        Set<String> creators = page.getData().stream()
                .map(MeasureConf::getCreatorCode)
                .filter(Objects::nonNull).collect(Collectors.toSet());
        Map<String, SysUser> creatorMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(creators)) {
            CSysUser cdt = new CSysUser();
            cdt.setLoginCodes(creators.toArray(new String[creators.size()]));
            List<SysUser> users = userApiSvc.getSysUserByCdt(cdt);
            if (!CollectionUtils.isEmpty(users)) {
                creatorMap = users.stream().collect(Collectors.toMap(SysUser::getLoginCode, Function.identity(), (k1,k2) -> k1));
            }
        }
        List<MeasureConfHistory> measureConfHistories = new ArrayList<>();
        for (MeasureConf conf : page.getData()) {
            MeasureConfHistory measureConfHistory = new MeasureConfHistory();
            measureConfHistory.setId(conf.getId());
            measureConfHistory.setVersion("V".concat(conf.getVersion().toString()));
            measureConfHistory.setModifier(conf.getCreatorCode());
            if (creatorMap.containsKey(conf.getCreatorCode())) {
                measureConfHistory.setModifier(creatorMap.get(conf.getCreatorCode()).getUserName());
            }
            measureConfHistory.setModifyTime(transDateFormat(conf.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
            measureConfHistories.add(measureConfHistory);
        }
        return measureConfHistories;
    }

    private String transDateFormat(Long date, String format) {
        if (date == null) {
            return "-";
        }
        SimpleDateFormat timeFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            return sdf.format(timeFormatter.parse(date.toString()));
        } catch (ParseException e) {
            log.error("时间格式转化失败:date:{},format:{}", date, format);
        }
        return "-";
    }

    @Override
    public void sst(Long id) {
        Assert.notNull(id, "度量id不能为空");
        MeasureConf measureConf = measureConfDao.getById(id);
        Assert.notNull(measureConf, "未找到度量信息");
        measureConf.setStatus(1 - measureConf.getStatus());
        measureConf.setModifierCode(SysUtil.getCurrentUserInfo().getLoginCode());
        measureConf.setModifyTime(ESUtil.getNumberDateTime());
        measureConfDao.saveOrUpdate(measureConf);
    }
}
